package com.example.chuzhou.config;


import com.alibaba.fastjson.JSONObject;
import com.example.chuzhou.util.CookieUtil;
import com.example.chuzhou.util.RedisUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;

import javax.annotation.Resource;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.time.Duration;
import java.util.*;

import static com.example.chuzhou.constans.CommonConstans.NO_LOGIN;
import static com.example.chuzhou.constans.CommonConstans.SESSION_KEY;


@WebFilter(filterName = "sessionFilter", urlPatterns = "/*")
@Slf4j
public class SessionFilter implements Filter {

    @Value(value = "${spring.profiles.active}")
    private String active;

    @Autowired
    RedisUtils redisUtils;


//    RedisTemplate<String, Object> redisTemplate;


    @SuppressWarnings("rawtypes")
    @Resource(name = "redisStringTemplate")
    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 不需要过滤的URL
     */
    private String[] filterExclusionUrls = {
            "/api/V1/cz/login",
            "/api/V1/cz/catoken",
            "/api/V1/cz/downloadCADrive",
            "/api/V1/cz/sendSms",
            "/api/V1/cz/smsLogin",
            "/api/V1/cz/changSec",
            "/portal/logout",
//            "/v2/api-docs",
//            "csrf",
//            "/swagger-resources",
//            "/swagger-resources/*",
//            "/swagger-resources/configuration/security",
//            "/swagger-ui.html",
//            "/doc.html",
//            "/webjars/*"
    };
//    private String[] filterExclusionUrls = { "*"};

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {


        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;
        String[] allowDomain = {
                //本地环境
                "http://127.0.0.1:8080",
                //生产环境 政务外网
                "http://59.203.54.206:60010",
                //生产环境 政务外网
                "https://59.203.54.206:60010",
                //生产环境 政务外网
                "https://59.203.54.206:18003",
                //生产环境 互联网
                "http://223.244.255.92:18002",
                //测试环境 政务内网
                "http://10.150.148.88:60010",
                //测试环境 政务外网
                "http://59.203.54.210:60010",

                "http://192.168.43.246:8080"
        };

        Set allowedOrigins = new HashSet(Arrays.asList(allowDomain));

        String originHeader = httpRequest.getHeader("Origin");
        log.info("originHeader = " + originHeader);
        if (allowedOrigins.contains(originHeader)) {

            httpResponse.setHeader("Access-Control-Allow-Origin", originHeader); // 设置允许对应跨域访问
            httpResponse.setHeader("Access-Control-Allow-Methods", "POST,GET,PUT,OPTIONS,DELETE");
            httpResponse.setHeader("Access-Control-Max-Age", "3600");
            httpResponse.setHeader("Access-Control-Allow-Headers", "Origin,X-Requested-With,Content-Type,Accept,Authorization,token");
            httpResponse.setHeader("Access-Control-Allow-Credentials", "true");
            httpResponse.setHeader("Access-Control-Expose-Headers", "*");
            // 6 检测到目标Content-Security-Policy响应头缺失 【可验证】
            httpResponse.setHeader("Content-Security-Policy", "default-src 'self'; script-src 'self'; frame-ancestors 'self'; object-src 'none'");
            // 9 检测到目标Strict-Transport-Security响应头缺失
            httpResponse.addHeader("Strict-Transport-Security", "max-age=63072000; includeSubdomains; preload");
            // 10 检测到目标X-Permitted-Cross-Domain-Policies响应头缺失
            httpResponse.setHeader("X-Permitted-Cross-Domain-Policies", "value");
            // 11 检测到目标X-Download-Options响应头缺失
            httpResponse.setHeader("X-Download-Options", "value");
            // 12 检测到目标Referrer-Policy响应头缺失
            httpResponse.setHeader("Referrer-Policy", "value");
            // 14 点击劫持：X-Frame-Options未配置 【可验证】
            httpResponse.setHeader("X-Frame-Options", "SAMEORIGIN");
            // 3 检测到目标X-XSS-Protection响应头缺失 【可验证】
            httpResponse.setHeader("X-XSS-Protection", "1;mode=block");
            // 2 检测到目标X-Content-Type-Options响应头缺失 【可验证】
            httpResponse.setHeader("X-Content-Type-Options", "nosniff");

            // 8 检测到目标服务器启用了OPTIONS方法 【可验证】 如果是OPTIONS则结束请求
            if (HttpMethod.OPTIONS.toString().equals(httpRequest.getMethod())) {
                httpResponse.setStatus(HttpStatus.NO_CONTENT.value());
                return;
            }
        }
        String url = httpRequest.getRequestURI().substring(httpRequest.getContextPath().length());
        log.info("url = " + url);
        if (isFliter(url)) {
            String sessionId = CookieUtil.getCookie(httpRequest, SESSION_KEY);
            log.info("sessionId:" + sessionId);
//            String sessionIdCheck = sessionId + "_check";
            if (null == redisTemplate.opsForValue().get(sessionId)) {
                synchronized (redisTemplate) {
                    if (null == redisTemplate.opsForValue().get(sessionId)) {
                        // session内容check
                        if (null == redisTemplate.opsForValue().get("ZHCS_" + sessionId)) {
                            redisTemplate.opsForValue().set(sessionId, "1", Duration.ofMillis(10000));
                            CookieUtil.deleteCookie(httpResponse, SESSION_KEY);
                            log.info("用户未登录！");
//                httpResponse.sendRedirect(httpRequest.getContextPath() + "/api/V1/cz/login");
//                return;
                            httpResponse.setContentType("text/html;charset=utf-8");
                            PrintWriter printWriter = httpResponse.getWriter();
                            Map<String, Object> result = new HashMap<>();
                            result.put("code", NO_LOGIN);
                            result.put("message", "用户未登录！");
                            result.put("success", false);
                            printWriter.write(JSONObject.toJSONString(result));
                            return;
                        }
                        chain.doFilter(request, response);
                        return;
                    } else {
                        return;
                    }
                }
            } else {
                return;
            }
        }
        chain.doFilter(request, response);
    }


    /**
     * 判断该url是否需要过滤
     *
     * @param url
     * @return
     */
    private boolean isFliter(String url) {
//        if ("dev".equals(active)) {
//            return false;
//        }
        for (String exclusion : filterExclusionUrls) {
            if (match(exclusion, url, 0, 0)) {
                return false;
            }
        }
        return true;
    }

    /**
     * 字符串通配符
     *
     * @param s1
     * @param s2
     * @param c1
     * @param c2
     * @return
     */
    public static boolean match(String s1, String s2, int c1, int c2) {
        if (c1 == s1.length() && c2 == s2.length()) {
            return true;
        }
        if (c1 == s1.length() || c2 == s2.length()) {
            return false;
        }
        if (s1.charAt(c1) == '?') {
            return match(s1, s2, c1 + 1, c2 + 1);
        } else if (s1.charAt(c1) == '*') {
            return match(s1, s2, c1 + 1, c2) || match(s1, s2, c1 + 1, c2 + 1) || match(s1, s2, c1, c2 + 1);
        } else if (s1.charAt(c1) == s2.charAt(c2)) {
            return match(s1, s2, c1 + 1, c2 + 1);
        } else {
            return false;
        }
    }

}
